package jdbc;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

import javax.sql.DataSource;

public class JDBCUtils {
    static String cfgFile= Paths.get(".").toAbsolutePath().normalize() +"/dbcp.properties";
    static FileInputStream is =null;
    //配置文件的操作类Properties类（java.util.Properties）
    static Properties properties=new Properties();
    static DataSource pool=null;
    //会话：登录系统后，可以进行多个操作,但只登录了一次
    //事务：每个操作，如第一次转账和第二次转账是两个事务
    //线程：一个人操作和多个人操作的问题
    //一个会话可以创建多个事务，一个事务只能由一个会话产生
    //一个事务可以产生多个线程，一个线程同一时间内只能由一个事务执行
    //创建事务，类之间互调属于同一个线程，为同一个线程保存同一个连接值conn,为不同线程保存不同的连接值
    //泛型里面可以放任意对象，用事务保存什么就放什么类型
    static ThreadLocal<Connection> tdl= new ThreadLocal<>();

    //创建连接池，并将dbcp.properties以键值对的形式读入
    static{
        //这个try是为createDataSource捕获的异常
        try {
            //JDBCUtils.class为JDBCUtils的字节码文件
            //当前class的包路径为基准，获取dbcp.properties文件的流
            is = new FileInputStream(cfgFile);

            //从输入流中以键值对的形式读取dbcp.propertie,要捕捉异常
            try {
                properties.load(is);
            } catch (IOException e) {
                e.printStackTrace();
            }

            //使用BasicDataSourceFactory数据连接池工厂类创建一个连接池
            //并将从dbcp.propertie读取出的键值对放入连接池中
            //System.out.println(properties);
            pool = BasicDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                //关闭流文件，捕获异常
                assert is != null;
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //获取连接
    public static Connection getConnection() throws Exception{
        //获取当前线程中拥有的连接,如果没有就创建一个
        Connection conn = tdl.get();
        if(conn==null){
            //从连接池中取值,并将连接加入当前线程中
            conn=pool.getConnection();
            tdl.set(conn);
        }
        return conn;
    }

    //释放资源
    //导包导的都是有关sql的包
    public static void release(ResultSet rs,PreparedStatement pstm,Connection conn) throws Exception{
        if(rs!=null){
            rs.close();
        }
        if(pstm!=null){
            pstm.close();
        }
        //关闭连接，同时将连接从当前线程中移除
        if(conn!=null){
            conn.close();
            tdl.remove();
        }
    }

}
